import path
import syscall
import libc
import libc.dirent
import runtime

type signal = u8

fn args():[string] {
    return libc.std_args()
}

// read current exe path by read link /proc/self/exe
fn exe():string! {
    var buf = vec_new<u8>(0, 4096)
    var len = syscall.readlink('/proc/self/exe', buf)

    buf = buf.slice(0, len)
    return buf as string
}

fn dirs_sort([string] dirs) {
    var n = dirs.len()
    for int i = 0; i < n-1; i+=1 {
        for int j = 0; j < n-i-1; j+=1 {
            if dirs[j] > dirs[j+1] {
                (dirs[j], dirs[j+1]) = (dirs[j+1], dirs[j])
            }
        }
    }
}

// unsafe ptr
// The order of return is uncertain
fn listdir(string path):[string]! {
    [string] result = []

    var dir = dirent.opendir(path.ref())
    if dir == 0 {
        throw errorf('opendir failed: ' + libc.error_string())
    }

    for true {
        // rawptr 可以接收 null 或者具体的指针值，可以通过 *语法解构原始值
        rawptr<dirent.dirent_t> entry = dirent.readdir(dir)
        if entry == null {
            break
        }

        var name = runtime.string_new(entry.name as anyptr)
        if name == '.' || name == '..' || name == '' {
            continue
        }

        result.push(name)
    }

    dirent.closedir(dir)
    dirs_sort(result)

    return result
}

// use dir.split(dir, '/')
// join and syscall.mkdir(dir, mode)
fn mkdirs(string dir, u32 mode):void! {
    if dir == '' {
        throw errorf('dir is empty')
    }

    if path.exists(dir) {
        return
    }

    // path not found will create
    var parent_dir = path.dir(dir)
    mkdirs(parent_dir, mode)

    // parent dir is create, will create dir
    syscall.mkdir(dir, mode)
}

// use remove file
fn remove(string full_path):void! {
    if !path.exists(full_path) {
        return
    }

    syscall.unlink(full_path)
}

fn rmdir(string dir, bool recursive):void! {
    if !recursive {
        return syscall.rmdir(dir)
    }

    var list = listdir(dir)
    for item in list {
        var fullpath = path.join(dir, item)
        var isdir = path.isdir(fullpath)
        if isdir {
            rmdir(fullpath, true) // 递归删除其中的所有文件
        } else {
            // rm file 可能存在权限不足的错误，暂时不做错误判断，直接跳过即可
            remove(fullpath) catch err {}
        }
    }

    // sub already remove, remove self
    syscall.rmdir(dir)
}